package com.gitee.clarence.interceptor.log;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.MDC;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.gitee.clarence.common.constant.Constant;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LogInterceptor extends HandlerInterceptorAdapter {

	private SerializerFeature[] features = new SerializerFeature[0];

	private SerializeFilter[] serialzeFilters = new SerializeFilter[0];

	private String dateFormat;

	private static final String X_B3_TRACEID = "X-B3-TraceId";
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		String preLogging = preLogging(request, response);
		log.info(preLogging);
		return true;// 只有返回true才会继续向下执行，返回false取消当前请求
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {

		String afterLogging = afterLogging(request, response);
		log.info(afterLogging);
	}

	private String preLogging(HttpServletRequest request, HttpServletResponse response) {

		String traceId = MDC.get(X_B3_TRACEID);

		final LoggingMessage buffer = new LoggingMessage("Inbound Message\n----------------------------", traceId);

		String encoding = (String) request.getCharacterEncoding();

		if (encoding != null) {
			buffer.getEncoding().append(encoding);
		}
		String httpMethod = (String) request.getMethod();
		if (httpMethod != null) {
			buffer.getHttpMethod().append(httpMethod);
		}
		String ct = (String) request.getContentType();
		if (ct != null) {
			buffer.getContentType().append(ct);
		}

		JSONObject headers = new JSONObject();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String headerName = (String) headerNames.nextElement();
			String headerValue = request.getHeader(headerName);
			headers.put(headerName, headerValue);
		}

		if (headers != null) {
			buffer.getHeader().append(headers);
		}

		StringBuffer address = request.getRequestURL();
		if (address != null) {
			buffer.getAddress().append(address);
		}

		return formatLoggingMessage(buffer);
	}

	private String afterLogging(HttpServletRequest request, HttpServletResponse response) {

		String traceId = MDC.get(X_B3_TRACEID);

		final LoggingMessage buffer = new LoggingMessage("Outbound Message\n---------------------------", traceId);

		Integer responseCode = (Integer) response.getStatus();
		if (responseCode != null) {
			buffer.getResponseCode().append(responseCode);
		}

		String encoding = (String) response.getCharacterEncoding();
		if (encoding != null) {
			buffer.getEncoding().append(encoding);
		}

		String httpMethod = (String) request.getMethod();
		if (httpMethod != null) {
			buffer.getHttpMethod().append(httpMethod);
		}

		StringBuffer address = request.getRequestURL();
		if (address != null) {
			buffer.getAddress().append(address);
		}

		String ct = (String) response.getContentType();
		if (ct != null) {
			buffer.getContentType().append(ct);
		}

		Object result = request.getAttribute(Constant.REQUEST_RESULT_KEY);
		if (result != null) {
			String text = JSON.toJSONString(result, //
					SerializeConfig.globalInstance, //
					serialzeFilters, //
					dateFormat, //
					JSON.DEFAULT_GENERATE_FEATURE, //
					features);
			buffer.getPayload().append(text);
		}

		return formatLoggingMessage(buffer);
	}

	private String formatLoggingMessage(LoggingMessage loggingMessage) {

		return loggingMessage.toString();
	}

}
